package com.cl.short_video_java.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.MD5;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.cl.short_video_java.common.Const;
import com.cl.short_video_java.dto.VideoCount;
import com.cl.short_video_java.mapper.VideoLikeCollectMapper;
import com.cl.short_video_java.mapper.VideoUserFollowedMapper;
import com.cl.short_video_java.mapper.VideoVideoMapper;
import com.cl.short_video_java.pojo.*;
import com.cl.short_video_java.service.*;
import com.cl.short_video_java.mapper.VideoUserMapper;

import com.cl.short_video_java.util.*;
import com.cl.short_video_java.vo.Login;
import com.cl.short_video_java.vo.Register;
import com.cl.short_video_java.vo.user.AddUserAdmin;
import com.cl.short_video_java.vo.user.FindPass;
import com.cl.short_video_java.vo.user.UserSearch;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;

/**
 * @author object
 * @description 针对表【video_user】的数据库操作Service实现
 * @createDate 2024-10-31 15:58:59
 */
@Service
@Slf4j
public class VideoUserServiceImpl extends ServiceImpl<VideoUserMapper, VideoUser>
		implements VideoUserService {

	private RedisUtil redisUtil;
	private SysLogininforService sysLogininforService;
	private JwtUtil jwtUtil;

	private VideoUserMapper videoUserMapper;
	private SysMediaService sysMediaService;
	private VideoShopService videoShopService;
	private SysSettingService sysSettingService;
	private VideoUserBalanceService videoUserBalanceService;
	VideoVideoMapper videoMapper;
	private VideoLikeCollectMapper collectMapper;
	private VideoUserFollowedMapper followedMapper;


	@Autowired
	public VideoUserServiceImpl(RedisUtil redisUtil,
								SysLogininforService sysLogininforService,
								JwtUtil jwtUtil,
								SysMediaService sysMediaService,
								VideoShopService videoShopService,
								SysSettingService sysSettingService,
								VideoUserBalanceService videoUserBalanceService,
								VideoLikeCollectMapper collectMapper,
								VideoVideoMapper videoMapper,
								VideoUserFollowedMapper followedMapper) {
		this.redisUtil = redisUtil;
		this.sysLogininforService = sysLogininforService;
		this.jwtUtil = jwtUtil;
		this.sysMediaService = sysMediaService;
		this.videoShopService = videoShopService;
		this.sysSettingService = sysSettingService;
		this.videoUserBalanceService = videoUserBalanceService;
		this.collectMapper = collectMapper;
		this.videoMapper = videoMapper;
		this.followedMapper = followedMapper;
	}

	/**
	 * 获取当前登录用户（弃用）
	 *
	 * @return
	 */
	@Override
	public VideoUser getCurrentUser() {
		String username = redisUtil.get("username");
		VideoUser user = this.getOne(new QueryWrapper<VideoUser>().eq(username != null, "username", username));
		Assert.notNull(user, "当前未登录");
		return user;
	}

	/**
	 * 获取当前登录用户
	 *
	 * @param request
	 * @return
	 */
	@Override
	public VideoUser getCurrentUser(HttpServletRequest request, String grade) {

		String token = request.getHeader("token");
		Claims claimByToken = jwtUtil.getClaimByToken(token, grade);
		String username = claimByToken.getSubject();
		VideoUser user = this.getOne(new QueryWrapper<VideoUser>().eq(username != null, "username", username));
		return user;
	}

	/**
	 * 注册账号
	 *
	 * @param register
	 * @param request
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Map<Object, Object> register(Register register, HttpServletRequest request) {
		VideoUser user1 = this.getOne(new QueryWrapper<VideoUser>().eq("username", register.getUsername()));
		Assert.isTrue(user1 == null, "抱歉，当前用户已存在");
		if (StringUtils.isNotEmpty(register.getEmail())) {
			long count = this.count(new QueryWrapper<VideoUser>().eq("email", register.getEmail()));
			Assert.isTrue(count ==0, "当前邮箱已被绑定");
		}

//		String s = redisUtil.get(register.getUuid());
//		Assert.isTrue(StringUtils.isEmpty(s) || s.equals(register.getCode()), "验证码错误");
		VideoUser user = new VideoUser();
		user.setUsername(register.getUsername());
		user.setPassword(MD5.create().digestHex16(register.getPassword()));
		user.setAddress("地球村");
		user.setBirth(LocalDateTime.now());
		DecimalFormat format = new DecimalFormat("#.##");
		user.setCreateTime(LocalDateTime.now());
		user.setBalance(Float.valueOf(format.format(0)));
		user.setLevel(0);
		user.setIsDelete(0);
		user.setSex(2);
		user.setIsAdmin(0);
		user.setNickname(NameUtil.getName());
		user.setEmail(register.getEmail() != null ? register.getEmail() : "");

		SysMedia one = sysMediaService.getOne(new QueryWrapper<SysMedia>().eq("id", RandomUtil.randomInt(1, 30)));
		user.setAvatar(one.getUrl());

		String l = IdAssignUtil.nextId();
		user.setPopularizeCode(l);
		this.save(user);
		sysLogininforService.addLog(request, user.getUsername(), "用户【" + user.getUsername() + "】登录了");
		String token = jwtUtil.generateToken(user.getUsername(), Const.GRADE_USER);
		user.setIssuer(Const.GRADE_USER);
		user.setPassword("");
		user.setIsAdmin(null);
		return MapUtil.builder().put("user", user).put("token", token).build();
	}

	@Override
	public Map<Object, Object> login(Login login, HttpServletRequest request) {
		long count = this.count(new QueryWrapper<VideoUser>()
				.eq("status", 1)
				.eq("is_delete", 0)
				.and(i -> i.like("username", login.getUsername()).or().like("email", login.getUsername()))

		);
		VideoUser user = new VideoUser();
		Assert.isTrue(count > 0, "账号或密码错误");
		user = this.getOne(new QueryWrapper<VideoUser>()
				.and(i -> i.like("username", login.getUsername()).or().like("email", login.getUsername()))
				.eq("password", MD5.create().digestHex16(login.getPassword())));
		Assert.isTrue(user != null, "账号或密码错误");
		String s = redisUtil.get(login.getUuid());
		Assert.isTrue(StringUtils.isEmpty(s) || s.toLowerCase().equals(login.getCode().toLowerCase()), "验证码错误");
		if (login.getType() == 0) {
			//管理后台
			Assert.isTrue(user.getIsAdmin() == 1, "抱歉，账号或密码错误");
		}

		sysLogininforService.addLog(request, user.getUsername(), "用户【" + user.getUsername() + "】登录了");
		String token = jwtUtil.generateToken(user.getUsername(), user.getIsAdmin() == 1 ? Const.GRADE_ADMIN : Const.GRADE_USER);
		user.setIssuer(login.getType() == 0 ? Const.GRADE_ADMIN : Const.GRADE_USER);
		user.setPassword("");
		user.setIsAdmin(null);
		return MapUtil.builder().put("user", user).put("token", token).build();
	}

	@Override
	public Boolean DeleteVideoUserByIdService(List<Integer> idlist) {
		boolean b = this.removeBatchByIds(idlist);
		return b;
	}

	@Override
	public Page<VideoUser> SelectAllVideoUserService(UserSearch userSearch) {
		Page<VideoUser> page = this.page(new Page<>(userSearch.getPageNum(), userSearch.getPageSize()), new QueryWrapper<VideoUser>()
				.like(StringUtils.isNotEmpty(userSearch.getUsername()), "username", userSearch.getUsername())
				.like(StringUtils.isNotEmpty(userSearch.getPhone()), "phone", userSearch.getPhone())
				.like(StringUtils.isNotEmpty(userSearch.getNickname()), "nickname", userSearch.getNickname())
				.eq(userSearch.getStatus() != null, "status", userSearch.getStatus())
				.eq("is_delete", 0)
				.ne("id", 1)
		);

		return page;

	}

	@Override
	public Boolean UpdataVideoUserLevelService(Integer id, Integer level) {
		boolean update = this.update(new UpdateWrapper<VideoUser>().eq("id", id).set("level", level));
		return update;
	}

	@Override
	public Boolean UpdataVideoUserIsAdminService(Integer id, Integer isadmin) {
		boolean update = this.update(new UpdateWrapper<VideoUser>().eq("id", id).set("is_admin", isadmin));
		return update;
	}

	/**
	 * 用户搜索
	 *
	 * @param userSearch 用户搜索参数
	 * @return
	 */
	@Override
	public List<VideoUser> search(UserSearch userSearch) {
		this.list(new QueryWrapper<VideoUser>()
				.like(StringUtils.isNotBlank(userSearch.getUsername()), "username", userSearch.getUsername())
				.eq("is_delete", 0)
		);
		return List.of();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void save(AddUserAdmin user) {
		VideoUser videoUser = new VideoUser();

		// 通过是否存在id来判断是新增还是修改，且判断当前用户是否已经存在
		if (user.getId() != null) {
			videoUser.setId(user.getId());
		} else {
			long count = this.count(new QueryWrapper<VideoUser>().eq("username", user.getUsername()));
			Assert.isTrue(count == 0, "当前账号已存在");
			String l = IdAssignUtil.nextId();
			videoUser.setPopularizeCode(l);
			SysMedia one = sysMediaService.getOne(new QueryWrapper<SysMedia>().eq("id", RandomUtil.randomInt(1, 18)));
			videoUser.setAvatar(one.getUrl());
		}

		// 修改的属性赋值
		// TODO 待优化
		if (StringUtils.isNotEmpty(user.getPhone())) {
			videoUser.setPhone(user.getPhone());
		}
		if (StringUtils.isNotEmpty(user.getAddress())) {
			videoUser.setAddress(user.getAddress());
		}
		if (StringUtils.isNotEmpty(user.getEmail())) {
			videoUser.setEmail(user.getEmail());
		}
		if (user.getBirth() != null) {
			videoUser.setBirth(user.getBirth());
		}
		videoUser.setUsername(user.getUsername());
		videoUser.setPassword(MD5.create().digestHex16(user.getPassword()));
		videoUser.setNickname(StringUtils.isNotEmpty(user.getNickname()) ? user.getNickname() : "");
		videoUser.setStatus(user.getStatus() != null ? user.getStatus() : 1);
		videoUser.setLevel(user.getLevel() != null ? user.getLevel() : 0);
		videoUser.setCreateTime(LocalDateTime.now());
		videoUser.setSex(2);
		videoUser.setIsAdmin(0);
		videoUser.setRegisterType(0);
		videoUser.setIsDelete(0);
		videoUser.setBalance(0.00F);
		this.saveOrUpdate(videoUser);
	}

	/**
	 * 解禁/封禁用户
	 *
	 * @param userId 用户id
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void limit(Integer userId) {
		VideoUser user = this.getById(userId);
		Assert.isTrue(StringUtils.isNotEmpty(user.getUsername()), "当前用户不存在，请刷新试试");
		this.update(new UpdateWrapper<VideoUser>().eq("id", userId).set("status", user.getStatus() == 1 ? 0 : 1));
	}

	/**
	 * 批量删除用户（虚拟删除）
	 *
	 * @param idList 用户id列表
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void del(List<Integer> idList) {
		for (Integer id : idList) {
			this.update(new UpdateWrapper<VideoUser>().eq("id", id).set("is_delete", 1));
		}
	}

	@Override
	public Page<VideoUser> vipUserList(UserSearch userSearch) {
		Page<VideoUser> page = this.page(new Page<>(userSearch.getPageNum(), userSearch.getPageSize()), new QueryWrapper<VideoUser>()
				.like(StringUtils.isNotEmpty(userSearch.getUsername()), "username", userSearch.getUsername())
				.like(StringUtils.isNotEmpty(userSearch.getPhone()), "phone", userSearch.getPhone())
				.like(StringUtils.isNotEmpty(userSearch.getNickname()), "nickname", userSearch.getNickname())
				.eq(userSearch.getStatus() != null, "status", userSearch.getStatus())
				.eq("is_delete", 0)
				.eq("level", 1)
		);

		return page;
	}

	/**
	 * 用户购买商品后的处理
	 *
	 * @param id
	 * @param userId
	 * @param price
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void upgrade(Integer id, Integer userId, BigDecimal price) {
		log.info("会员处理=================");
		VideoShop videoShop = videoShopService.getById(id);
		VideoUser user = this.getOne(new QueryWrapper<VideoUser>().eq("id", userId));
		if (videoShop.getType() == 1) {
			log.info("会员购买=================");
			// 会员商品
			Integer date = videoShop.getDate();
			// 0-年，1-天，2-月
			Integer dateUnit = videoShop.getDateUnit();
			LocalDateTime time = getTime(date, dateUnit);

			if (user.getLevel() == 1) {
				log.info("续费========" + dateUnit);
				// 这就是会员
				LocalDateTime otime = user.getOtime();
				if (dateUnit == 0) {
					otime.plusYears(date);
				} else if (dateUnit == 2) {
					otime.plusMonths(date);
				} else if (dateUnit == 1) {
					otime.plusDays(date);
				}
				user.setOtime(otime);
				this.updateById(user);
			} else {
				log.info("开通========" + dateUnit);
				this.update(new UpdateWrapper<VideoUser>()
						.eq("id", userId)
						.set("level", 1)
						.set("atime", LocalDateTime.now())
						.set("otime", time)
				);
			}

		} else {
			log.info("金币购买=================");
			// 金币
			String rate = sysSettingService.getSysSettingByKey("sys_exchange_rate");
			BigDecimal balance = videoShop.getPrice().multiply(new BigDecimal(rate));
			log.info("金币购买================={}", user.getBalance() + balance.floatValue());
			this.update(new UpdateWrapper<VideoUser>().eq("id", userId).set("balance", user.getBalance() + balance.floatValue()));
		}
		// 添加购买信息
		videoUserBalanceService.addBalance(userId, price, id);
	}

	@Override
	public void addBalance(Integer userId, BigDecimal balance) {
		VideoUser user = this.getOne(new QueryWrapper<VideoUser>().eq("id", userId));
		float v = balance.floatValue();
		user.setBalance(v);
		this.updateById(user);
	}

	@Override
	public String account() {
		String randomString = "";
		Integer len = Integer.valueOf(sysSettingService.getSysSettingByKey("sys_account_len"));
		boolean flag = true;
		while (flag) {
			randomString = RandomStringUtils.randomNumeric(len);
			VideoUser user = this.getOne(new QueryWrapper<VideoUser>().eq("username", randomString));
			if (user == null) {
				flag = false;
			}
		}

		return randomString;
	}

	@Override
	public Boolean publiShingService(Integer id, Integer isPubliShing) {
		boolean update = this.update(new UpdateWrapper<VideoUser>()
				.eq("id", id)
				.set("is_publish", isPubliShing == 0 ? 1 : 0));

		return update;
	}

	/**
	 * 获取用户信息
	 * 用于他人访问
	 *
	 * @param uid 用户id
	 * @return
	 */
	@Override
	public VideoUser info(Integer uid) {
		Assert.isTrue(uid != null, "未找到用户信息");
		VideoUser videoUser = this.getById(uid);
		videoUser.setPassword("");
		// 获取视频总量计算
		VideoCount count = videoMapper.allCount(videoUser.getId());
		videoUser.setVideoCounts(count);
		// 获取粉丝数量
		long collects = followedMapper.selectCount(new QueryWrapper<VideoUserFollowed>()
				.eq("followed_uid", videoUser.getId())
				.eq("status", 1));
		videoUser.setCollects(collects);
		return videoUser;
	}

	/**
	 * 找回密码
	 *
	 * @param findPass
	 */
	@Override
	public void findPass(FindPass findPass) {
		VideoUser user = this.getOne(new QueryWrapper<VideoUser>()
				.eq("email", findPass.getEmail())
				.eq("status", 1)
				.eq("is_delete", 0)
				.last("limit 1")
		);
		Assert.isTrue(user.getId() != null, "抱歉，邮箱绑定用户不存在");

		String s = redisUtil.get("mail" + user.getEmail());
		Assert.isTrue(StringUtils.isNotEmpty(s), "验证码已过期");
		Assert.isTrue(findPass.getCode().equals(s), "抱歉，验证码错误");
		user.setPassword(MD5.create().digestHex16(findPass.getPass()));

		this.updateById(user);
	}

	/**
	 * 绑定邮箱
	 *
	 * @param email
	 * @param code
	 * @param user
	 */
	@Override
	public void bindEmail(String email, String code, VideoUser user) {
		String s = redisUtil.get("mail" + email);
		Assert.isTrue(StringUtils.isNotEmpty(s), "验证码已过期");
		Assert.isTrue(code.equals(s), "抱歉，验证码错误");

		long count = this.count(new QueryWrapper<VideoUser>().eq("email", email));
		Assert.isTrue(count == 0, "当前邮箱已被绑定");
		user.setEmail(email);
		this.updateById(user);

	}

	private LocalDateTime getTime(Integer date, Integer type) {
		LocalDateTime now = LocalDateTime.now();
		if (type == 1) {
			// 天
			return now.plus(date, ChronoUnit.DAYS);
		} else if (type == 2) {
			// 月
			return now.plus(date, ChronoUnit.MONTHS);
		} else {
			// 年
			return now.plus(date, ChronoUnit.YEARS);
		}
	}
}




